with Text_Builder;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
package Ada_Builder is

   type Ada_Builder_Type is new Text_Builder.Builder_Type with private;

   procedure Define_New_Scalar (
      this : in out Ada_Builder_Type;
      Name : String;
      Base : String := "";
      Min  : String := "";
      Max  : String := ""
      );

   procedure Define_Sub_Scalar (
      this : in out Ada_Builder_Type;
      Name : String;
      Base : String;
      Min  : String := "";
      Max  : String := ""
      );

   procedure Define_Private (
      this : in out Ada_Builder_Type;
      Name : String;
      Disc : String := "";
      Base : String := "";
      Limit : Boolean := False
      );

   procedure Define_Var (
      this : in out Ada_Builder_Type;
      Name : String;
      Type_Name : String;
      Init_Value : String := ""
      );

   procedure Define_Param (
      this       : in out Ada_Builder_Type;
      Name       : String;
      Type_Name  : String;
      Init_Value : String := ""
      );

   -- if any parameters, Define_Param should call first
   procedure Define_Proc (
      this : in out Ada_Builder_Type;
      Name : String;
      Spec : Boolean := True
      );

   -- if any parameters, Define_Param should call first
   procedure Define_Entry (
      this : in out Ada_Builder_Type;
      Name : String;
      Spec : Boolean := True 
      );

   -- if any parameters, Define_Param should call first
   procedure Define_Func (
      this        : in out Ada_Builder_Type;
      Name        : String;
      Result_Type : String;
      Spec        : Boolean := True
      );

   procedure End_Indent (this : in out Ada_Builder_Type);

   procedure End_Define (this : in out Ada_Builder_Type);

   procedure End_Block (this : in out Ada_Builder_Type);

   procedure End_Statement (this : in out Ada_Builder_Type);

   procedure Push_Parameter (
      this : in out Ada_Builder_Type;
      Expr : String;
      Name : String := ""
      );

   -- if any parameters, Push_Parameter should call first
   procedure Call_Proc (
      this : in out Ada_Builder_Type;
      Name : String
      );

   -- if any parameters, Push_Parameter should call first
   -- if Assign_To is not empty then assignment statement yield 
   procedure Calc_Func (
      this      : in out Ada_Builder_Type;
      Name      : String;
      Assign_To : String := ""
      );

   procedure Return_Expr (
      this   : in out Ada_Builder_Type;
      Expr   : String := "";
      Simple : Boolean := True
      );

   procedure End_Return (this : in out Ada_Builder_Type);

   procedure Comment (
      this : in out Ada_Builder_Type;
      Line : String
      );

   procedure Begin_Block (
      this : in out Ada_Builder_Type;
      Name : String;
      Kind : String -- package procedure ...
      );

   procedure Begin_Is (
      this : in out Ada_Builder_Type;
      Single_Line : Boolean := False 
      );

   procedure Begin_Begin (this : in out Ada_Builder_Type);

   procedure Begin_Decl (this : in out Ada_Builder_Type);

   procedure Begin_Do (this : in out Ada_Builder_Type);

   procedure Begin_If (
      this : in out Ada_Builder_Type;
      Expr : String
      );

   procedure Begin_Elsif (
      this : in out Ada_Builder_Type;
      Expr : String
      );

   procedure Begin_Else (this : in out Ada_Builder_Type);

   procedure End_If (this : in out Ada_Builder_Type);

   procedure Begin_Loop (this : in out Ada_Builder_Type);

   procedure End_Loop (this : in out Ada_Builder_Type);

   procedure Begin_For_Loop (
      this : in out Ada_Builder_Type;
      I : String;
      R : String
      );

   procedure Begin_Foreach_Loop (
      this : in out Ada_Builder_Type;
      I : String;
      R : String
      );

   procedure Begin_While_Loop (
      this : in out Ada_Builder_Type;
      Expr : String
      );

   procedure Exit_Loop (
      this      : in out Ada_Builder_Type;
      Loop_Name : String := "";
      When_Expr : String := ""
      );

   procedure Append_Statement (
      this : in out Ada_Builder_Type;
      Line : String
      );

   procedure Begin_Task_Select (this : in out Ada_Builder_Type);

   procedure End_Task_Select (this : in out Ada_Builder_Type);

   procedure Begin_Task_Or (this : in out Ada_Builder_Type);

   procedure Begin_Task_Else (this : in out Ada_Builder_Type);

   procedure Begin_Task_Then_Abort (this : in out Ada_Builder_Type);

private

   package String_Lists is new Indefinite_Doubly_Linked_Lists(String);

   type Ada_Builder_Type is new Text_Builder.Builder_Type with record
      F_Blocks : String_Lists.List;
      F_Parameter_Names : String_Lists.List;
      F_Parameter_Types : String_Lists.List;
      F_Parameter_Inits : String_Lists.List;
      F_Parameter_Stack : String_Lists.List;
   end record;

end Ada_Builder;
